﻿using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.Runtime.Serialization;
using System.Collections;
using System.Reflection;
using MCMLXVII.BackEnd.Data.SystemDatabase;
using MCMLXVII.BackEnd.Data.OrganizationChart;
using MCMLXVII.BackEnd.Services.Common.Messages;

namespace MCMLXVII.Backend.Services.WCF
{
    class NodeAccessAuthorizationInvoker : IOperationInvoker
    {

        IOperationInvoker BaseInvoker;
        string _AccessLevel;

        public NodeAccessAuthorizationInvoker(IOperationInvoker BaseInvoker, string AccessLevel)
        {
            this.BaseInvoker = BaseInvoker;
            _AccessLevel = AccessLevel; 
        }
    
        #region IOperationInvoker Members

        public object[] AllocateInputs()
        {
            return this.BaseInvoker.AllocateInputs();
        }


        public object Invoke(object instance, object[] inputs, out object[] outputs)
        {

            outputs = new object[0];
            int nodeID = ((IOrganizationTreeNodeOperation)inputs[0]).NodeID;
            if (CheckAccessToNode(nodeID, _AccessLevel))
                return this.BaseInvoker.Invoke(instance, inputs, out outputs);
            else
                throw new FaultException<BackendFault>(new BackendFault(BackendFaulType.Security, "Access Denied"));
        }


        private bool CheckAccessToNode(int NodeID, string AccessLevel)
        {
            int MemberID = Security.GetMemberIDFromSession();
            string[] Permissions = TreeAndNodes.GetOrganizationTreeNodeEfectiveRights(NodeID, MemberID);

            foreach (string Permission in Permissions)
            {
                switch (AccessLevel)
                {
                    case "R": //Read
                        if (Permission == "R" || Permission == "F" || Permission == "S")
                            return true;
                        break;
                    case "C": //Create Child Nodes
                        if (Permission == "C" || Permission == "F")
                            return true;
                        break;
                    case "D": //Delete Node
                        if (Permission == "D" || Permission == "F")
                            return true;
                        break;
                    case "F": //Full Control
                        if (Permission == "F")
                            return true;
                        break;
                    case "S": //Manage Security
                        if (Permission == "F" || Permission == "S")
                            return true;
                        break;
                    case "E": //Edit Contents
                        if (Permission == "E" || Permission == "F")
                            return true;
                        break;
                    case "U": //Update Node
                        if (Permission == "U" || Permission == "F")
                            return true;
                        break;
                    case "A": //Audit node
                        if (Permission == "A")
                            return true;
                        break;
                }
            }
            return false;
        }



        public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
        {
            throw new Exception("InvokeBegin method not Implemented");
        }

        public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
        {
            throw new Exception("InvokeEnd method not Implemented");
        }

        public bool IsSynchronous
        {
            get { return true; }
        }

        #endregion
    }

    class NodeAccessAuthorizationBehaviour: Attribute, IOperationBehavior
    {
        private string _Accesslevel;

        #region IOperationBehavior Members
        public NodeAccessAuthorizationBehaviour(string AccessLevel)
        {
            _Accesslevel = AccessLevel;
                
        }
        public void AddBindingParameters(OperationDescription description, System.ServiceModel.Channels.BindingParameterCollection parameters)
        {
            
        }

        public void ApplyClientBehavior(OperationDescription description, ClientOperation proxy)
        {
            
        }

        public void ApplyDispatchBehavior(OperationDescription description, DispatchOperation dispatch)
        {
            dispatch.Invoker = new NodeAccessAuthorizationInvoker(dispatch.Invoker, _Accesslevel );
        }

        public void Validate(OperationDescription description)
        {
            
        }

        #endregion
    }
     
}
